jQuery.fn.highlight = function(pat) {
 function innerHighlight(node, pat) {
  var skip = 0;
  if (node.nodeType == 3) {
   var pos = node.data.toUpperCase().indexOf(pat);
   if (pos >= 0) {
    var spannode = document.createElement('span');
    spannode.className = 'highlight';
    var middlebit = node.splitText(pos);
    var endbit = middlebit.splitText(pat.length);
    var middleclone = middlebit.cloneNode(true);
    spannode.appendChild(middleclone);
    middlebit.parentNode.replaceChild(spannode, middlebit);
    skip = 1;
   }
  }
  else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
   for (var i = 0; i < node.childNodes.length; ++i) {
    i += innerHighlight(node.childNodes[i], pat);
   }
  }
  return skip;
 }
 return this.each(function() {
  innerHighlight(this, pat.toUpperCase());
 });
};

jQuery.fn.removeHighlight = function() {
 return this.find("span.highlight").each(function() {
  this.parentNode.firstChild.nodeName;
  with (this.parentNode) {
   replaceChild(this.firstChild, this);
   normalize();
  }
 }).end();
};

jQuery.dynaCloud = {

 max: 10,
 sort: true,
 auto: true,
 single: true,
 wordStats: true,
 scale: 4,

 stopwords: ["a","aca", "ademas", "ahi", "ahora", "al","algo", "alguien", "algun","alguna","algunas","alguno","algunos","alla","alli","ambos","ante","antes","aquel","aquella","aquellas","aquello","aquellos","aqui","arriba","asi","atras","aun","aunque","bajo","bastante","bien", "bueno", "cabe","cada","casi","cierta","ciertas","cierto","ciertos","como","con","conmigo","conseguimos","conseguir","consigo","consigue","consiguen","consigues","contigo","contra","creo","cual","cuales","cualquier","cualquiera","cualquieras","cuan","cuando","cuanta","cuantas","cuanto","cuánto","cuantos","cuántos","de","del","demas","demasiada","demasiadas","demasiado","demasiados","dice","digo","dile", "dentro","desde","donde","dos","el","ella","ellas","ello","ellos","en","encima","entonces","entre","era","eramos","eran","eras","eres","es","esa","esas","ese","eso","esos","espero", "esta","estaba","estado","estais","estamos","estan","estar", "estaria", "estas","este","esto","estos","estoy","etc","fin","fue","fueron","fui","fuimos","ha","hace","haceis","hacemos","hacen","hacer","haces","hacia","hago","hasta","ir","jamas","junto","juntos","la","las","lo","los","luego", "mas","me","menos","mi","mia","mias","mientras","mio","mios","mis","misma","mismas","mismo","mismos","modo","mucha","muchas","muchisima","muchisimas","muchisimo","muchisimos","mucho","muchos","muy","nada","ni","ningun","ninguna","ningunas","ninguno","ningunos","no","nos","nosotras","nosotros","nuestra","nuestras","nuestro","nuestros","nunca","os","otra","otras","otro","otros","para","parecer","pero","poca","pocas","poco","pocos","podeis","podemos","poder","podria","podriais","podriamos","podrian","podrias","por","porque","puede","pueden","puedo","pues","que","quien","quienes","quienesquiera","quienquiera","quiza","quizas","sabe","sabeis","sabemos","saben","saber","sabes","se","segun","ser","si","siempre","siendo","sin","sino","so","sobre","sois","solamente","solo","somos","soy","sr","sra","sres","sta","su","sus","suya","suyas","suyo","suyos","tal","tales","tambien","tampoco","tan","tanta","tantas","tanto","tantos","te","teneis","tenemos","tener","tengo","ti","tiempo","tiene","tienen","toda","todas","todo","todos","tras","tu","tus","tuya","tuyo","tuyos","ultimo","un","una","unas","uno","unos","usted","ustedes","va","vais","valor","vamos","van","varias","varios","vaya","verdadera","vosotras","vosotros","voy","vuestra","vuestras","vuestro","vuestros","y","ya","yo"]

};

jQuery(function() {
 jQuery.dynaCloud.stopwords = new RegExp("\\s((" + jQuery.dynaCloud.stopwords.join("|") + ")\\s)+", "gi");
 if (jQuery.dynaCloud.auto) {
  jQuery('.dynacloud').dynaCloud();
 }
});

jQuery.fn.dynaCloud = function(outElement) {
 var cloud = {};
 return this.each(function() {

  var cl = [];
  var max = 0;

  if (jQuery.wordStats && jQuery.dynaCloud.wordStats) {
   jQuery.wordStats.computeTopWords(jQuery.dynaCloud.max, this);
   for (var i = 0, j = jQuery.wordStats.topWords.length; i < j && i <= jQuery.dynaCloud.max; ++i) {
    var t = jQuery.wordStats.topWords[i].substring(1);
    if (typeof cloud[t] == 'undefined') {
     cloud[t] = { count: jQuery.wordStats.topWeights[i], el: t };
    }
    else {
     cloud[t].count += jQuery.wordStats.topWeights[i];
    }
    max = Math.max(cloud[t].count, max);
   }
   jQuery.wordStats.clear();
  }
  else {
   var elems = jQuery(this).text().replace(/[^A-Z\xC4\xD6\xDCa-z\xE4\xF6\xFC\xDF0-9_]/g, ' ').replace(jQuery.dynaCloud.stopwords, ' ').split(' ');
   var word = /^[a-z\xE4\xF6\xFC]*[A-Z\xC4\xD6\xDC]([A-Z\xC4\xD6\xDC\xDF]+|[a-z\xE4\xF6\xFC\xDF]{3,})/;

   jQuery.each(elems, function(i, n) {
    if (word.test(n)) {
     var t = n.toLowerCase();
     if (typeof cloud[t] == 'undefined') {
      cloud[t] = { count: 1, el: n };
     }
     else {
      cloud[t].count += 1;
     }
     max = Math.max(cloud[t].count, max);
    }
   });
  }

  jQuery.each(cloud, function(i, n) {
   cl[cl.length] = n;
  });

  if (jQuery.dynaCloud.sort) {
   cl.sort(function(a, b) {
    if (a.count == b.count) {
     return a.el < b.el ? -1 : (a.el == b.el ? 0 : 1);
    }
    else {
     return a.count < b.count ? 1 : -1;
    }
   });
  }

  var out;
  if ((out = jQuery(outElement ? outElement : '#dynacloud')).length == 0) {
   jQuery(document.body).append('<p id="dynacloud"><\/p>');
   out = jQuery('#dynacloud');
  }

  out.empty();

  var l = jQuery.dynaCloud.max == -1 ? cl.length : Math.min(jQuery.dynaCloud.max, cl.length);

  for (var i = 0; i < l; ++i) {
   out.append('<a href="#' + cl[i].el + '" style="font-size: ' + Math.ceil((cl[i].count / max) * jQuery.dynaCloud.scale) + 'em"><span>' + cl[i].el + '</span></a> &nbsp; ');
  }
  
  var target = this;

  jQuery('a', out).each(function() {
   jQuery(this).click(function() {

    if (jQuery.dynaCloud.single) {
     jQuery(document.body).removeHighlight();
    }

    var text = jQuery(this).text().toUpperCase();
    jQuery(target).each(function() {
     jQuery(this).highlight(text);
    });
    return false;
   });
  });

 });
};
